/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.dwh.trigger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import static org.dwh.trigger.Log.*;

/**
 *
 * @author Jose Carlos Palma
 */
public class SLUReader extends Thread {

    /**
     * Almacena informacion sobre la SLU (segun el archivo de configuracion).
     *
     * @see org.dwh.trigger.Conf#getSLUsInfo()
     */
    private SLUInfo info;
    /**
     * Almacena informacion del enlace de red con la SLU.
     */
    private Socket slu;
    /**
     * Contiene el enlace de escritura con el cliente.
     */
    private PrintWriter pw;
    /**
     * Contiene el enlace de lectura con el cliente.
     */
    private BufferedReader br;
    /**
     * Indica si el hilo se esta o no ejecutando.
     */
    private boolean running = false;
    /**
     * Indica que el hilo termino su ejecucion
     */
    private boolean shutdown = true;

    /**
     *
     * @param slu
     * @param info
     */
    public SLUReader(Socket slu, SLUInfo info) {
        this.slu = slu;
        try {
            this.slu.setSoTimeout(10000);
        } catch (SocketException ex) {
        }
        this.info = info;
        setName("SLU - " + info.getName() + "-" + info.getSdp());
    }

    /**
     *
     */
    public void turnOff() {
        this.running = false;
        try {
            if (slu != null) {
                this.slu.close();
            }
        } catch (IOException ex) {
        }
    }

    /**
     *
     * @return
     */
    public boolean isRunning() {
        return this.running;
    }

    /**
     *
     * @return
     */
    public boolean isShutdown() {
        return this.shutdown;
    }

    /**
     *
     */
    @Override
    public void run() {
        //Verifica si la cola esta activa o inactiva
        if (info.isOff()) {
            info("SLU: " + info.getName() + "[" + info.getStatus() + "]");
            return;
        }

        info("SLU: " + info.getName() + " is starting...");


        try {
            info("SLU: " + info.getName() + " get output...");
            pw = new PrintWriter(slu.getOutputStream(), true);
            info("SLU: " + info.getName() + " get input...");
            br = new BufferedReader(new InputStreamReader(slu.getInputStream()));
            info("Queue: " + info.getName() + " connect.");
        } catch (IOException ex) {
            error("Queue: " + info.getName() + " [IOException] can't to connect, "
                    + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
            Runtime.getRuntime().exit(1);
        }

        this.shutdown = false;
        this.running = true;
        info("SLU: " + info.getName() + " is running...");
        //Ciclo que recibe
        while (running && slu.isConnected()) {

            char c = ' ';

            StringBuilder sb = new StringBuilder();

            try {
                //Busca el inicio de un trigger (comienza con T)
                c = (char) slu.getInputStream().read();
                while (c != 'T' && running && slu.isConnected()) {
                    c = (char) slu.getInputStream().read();
                }
            } catch (SocketTimeoutException ex) {
                warning("SLU: " + info.getName() + " [SocketTimeoutException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                continue;
            } catch (IOException ex) {
                error("SLU: " + info.getName() + " [IOException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                break;
            }

            sb.append(c);

            try {
                //Busca el inicio de un trigger (comienza con T)
                c = (char) slu.getInputStream().read();
                while (c != ' ' && running && slu.isConnected()) {
                    sb.append(c);
                    c = (char) slu.getInputStream().read();
                }
            } catch (SocketTimeoutException ex) {
                warning("SLU: " + info.getName() + "  [SocketTimeoutException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                continue;
            } catch (IOException ex) {
                error("SLU: " + info.getName() + " [IOException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                break;
            }

            String type = sb.toString().trim();
            sb.append(c);

            try {
                //Busca el inicio de un trigger (comienza con T)
                c = (char) slu.getInputStream().read();
                while (c != ';' && running && slu.isConnected()) {
                    sb.append(c);
                    c = (char) slu.getInputStream().read();
                }
            } catch (SocketTimeoutException ex) {
                warning("SLU: " + info.getName() + "  [SocketTimeoutException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                continue;
            } catch (IOException ex) {
                error("SLU: " + info.getName() + " [IOException] can't to read, "
                        + (ex.getStackTrace() != null ? ex.getStackTrace()[ex.getStackTrace().length - 1] : ex.getMessage()));
                break;
            }


            QueueWriter qw = Server.hashQueues.get(type);

            if (qw != null) {
                Trigger t = new Trigger(sb, type, info.getName(), qw.getInfo().getName());
                qw.addTrigger(t);
            } else {
                Trigger t = new Trigger(sb, type, info.getName(), "XXX");
                reject(t);
            }

        }
        info("SLU: " + info.getName() + " is shuting down...");

        try {
            slu.close();
        } catch (IOException ex) {
        }

        this.shutdown = true;

        info("SLU: " + info.getName() + " is shutdown");
    }

    /**
     *
     * @return
     */
    public SLUInfo getInfo() {
        return this.info;
    }
}
